using System;
using System.IO;
using System.Text;
using Oracle.ManagedDataAccess.Client;
using Oracle.ManagedDataAccess.Types;
using OracleInternal.I18N;

namespace OracleInternal.BinXml
{
	internal class ObxmlStream : IDisposable
	{
		internal static readonly long sUseCurrentOffset = -1L;

		private BinXmlArrayStream m_DataStream;

		private bool m_Disposed;

		private const int DefaultUnicodeStringSize = 16384;

		private char[] m_UnicodeArray = new char[16384];

		private bool m_UnicodeArrayInUse;

		private object m_nlsLock = new object();

		internal static Conv Unicode_AL16UTF16_CHARSET = new UTF16ConvAL16UTF16(2000);

		internal static Conv Utf8_AL32UTF8_CHARSET = new UTF16ConvAL32UTF8(873);

		private ObxmlContentObject m_contentObj;

		private char[] m_temp = new char[512];

		internal long Position
		{
			get
			{
				return m_DataStream.Position;
			}
			set
			{
				m_DataStream.Position = value;
			}
		}

		internal ObxmlStream(ObxmlContentObject contentObj)
		{
			if (!contentObj.IsContentValid())
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.RequestInputInvalid));
			}
			m_contentObj = contentObj;
			if (contentObj.InputType == InputOutputTypes.ByteArray)
			{
				m_DataStream = new BinXmlArrayStream((byte[])contentObj.ContentObject, contentObj.InputLength);
			}
			m_DataStream.Init();
		}

		public void Dispose()
		{
			Close();
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!m_Disposed)
			{
				if (disposing && m_DataStream != null)
				{
					m_DataStream.Dispose();
					m_DataStream = null;
				}
				m_Disposed = true;
			}
		}

		internal Stream Open(string filePath)
		{
			return null;
		}

		internal Stream Open(OracleBlob blob)
		{
			return null;
		}

		internal void Close()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		internal void ReadAndCopyBytes(byte[] destination, long offset, long count)
		{
			m_DataStream.ReadAndCopyBytes(destination, (int)offset, (int)count);
		}

		internal byte[] ReadBytes(int count)
		{
			return m_DataStream.ReadBytes(count);
		}

		internal void SkipBytes(int count)
		{
			m_DataStream.Position += count;
		}

		internal byte[] ReadAllBytes(int offset)
		{
			return m_DataStream.ReadAllBytes(offset);
		}

		internal short ReadShortIntFromByte()
		{
			short num = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				num = ((byte[])m_contentObj.ContentObject)[Position];
				Position++;
			}
			else
			{
				num = m_DataStream.ReadByte();
			}
			return num;
		}

		internal short ReadShortInt()
		{
			byte[] array = null;
			int num = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				array = (byte[])m_contentObj.ContentObject;
				num = (int)Position;
			}
			else
			{
				array = ReadBytes(2);
			}
			short result = BitConverter.ToInt16(Reverse(array, 2, num), num);
			if (num != 0)
			{
				Position += 2L;
			}
			return result;
		}

		internal int ReadInt4()
		{
			int num = 4;
			byte[] array = null;
			int num2 = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				array = (byte[])m_contentObj.ContentObject;
				num2 = (int)Position;
			}
			else
			{
				array = ReadBytes(num);
			}
			int result = BitConverter.ToInt32(Reverse(array, num, num2), num2);
			if (num2 != 0)
			{
				Position += num;
			}
			return result;
		}

		internal long ReadInt8()
		{
			int num = 8;
			byte[] array = null;
			int num2 = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				array = (byte[])m_contentObj.ContentObject;
				num2 = (int)Position;
			}
			else
			{
				array = ReadBytes(num);
			}
			long result = BitConverter.ToInt64(Reverse(array, num, num2), num2);
			if (num2 != 0)
			{
				Position += num;
			}
			return result;
		}

		internal char ReadChar()
		{
			return BitConverter.ToChar(Reverse(m_DataStream.ReadBytes(2), 2), 0);
		}

		internal char[] ReadChar(int count)
		{
			char[] array = m_temp;
			if (count > 512)
			{
				array = new char[count];
			}
			for (int i = 0; i < count; i++)
			{
				byte[] array2 = m_DataStream.ReadBytes(2);
				array[i] = BitConverter.ToChar(Reverse(array2, 2), 0);
			}
			return array;
		}

		internal int ReadUtf8StringSB(ulong length, StringBuilder sb, Conv.DelegateReplaceCharsInSB replaceDelegate = null)
		{
			if (length == 0)
			{
				return 0;
			}
			int charsConverted = 0;
			byte[] array = null;
			int num = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				array = (byte[])m_contentObj.ContentObject;
				num = (int)Position;
			}
			else
			{
				array = ReadBytes((int)length);
			}
			if ((int)length < m_UnicodeArray.Length - 1)
			{
				Utf8_AL32UTF8_CHARSET.ConvertBytesToStringSB(sb, array, num, (int)length, ref charsConverted, m_UnicodeArray, 0, replaceDelegate);
				Position += (int)length;
				return charsConverted;
			}
			Utf8_AL32UTF8_CHARSET.ConvertBytesToStringSB(sb, array, num, (int)length, ref charsConverted, null, 0, replaceDelegate);
			if (num != 0)
			{
				Position += (int)length;
			}
			return charsConverted;
		}

		internal int ReadUtf8StringChar(int length, ObxmlInstructionState currentInstruction)
		{
			if (length <= 0)
			{
				return 1;
			}
			int charCount = length;
			byte[] array = null;
			int num = 0;
			int num2 = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				array = (byte[])m_contentObj.ContentObject;
				num2 = (int)Position;
			}
			else
			{
				array = ReadBytes(length);
			}
			if (length < currentInstruction.m_TextOrTokenData.Length)
			{
				num = Utf8_AL32UTF8_CHARSET.ConvertBytesToChars(array, num2, length, currentInstruction.m_TextOrTokenData, (int)currentInstruction.m_TokenOrDataLength, ref charCount);
				if (num2 != 0)
				{
					Position += num;
					currentInstruction.m_TokenOrDataLength += charCount;
				}
				return charCount;
			}
			return 0;
		}

		internal string ReadUtf8String(ulong length, StringBuilder sb = null)
		{
			if (length == 0)
			{
				return null;
			}
			byte[] array = null;
			int num = 0;
			if (m_contentObj.InputType == InputOutputTypes.ByteArray)
			{
				array = (byte[])m_contentObj.ContentObject;
				num = (int)Position;
			}
			else
			{
				array = ReadBytes((int)length);
			}
			string text = string.Empty;
			if ((int)length < m_UnicodeArray.Length - 1)
			{
				text = Utf8_AL32UTF8_CHARSET.ConvertBytesToString(array, num, (int)length, m_UnicodeArray);
				Position += (long)length;
			}
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			text = Utf8_AL32UTF8_CHARSET.ConvertBytesToString(array, num, (int)length);
			if (num != 0)
			{
				Position += (int)length;
			}
			return text;
		}

		internal static byte[] Reverse(byte[] array, int count, int startpost = 0)
		{
			byte b = 0;
			int num = startpost;
			int num2 = startpost + count - 1;
			while (num < startpost + count / 2 && num2 > num)
			{
				b = array[num];
				array[num] = array[num2];
				array[num2] = b;
				num++;
				num2--;
			}
			return array;
		}
	}
}
